home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Environments
/
Clean 1.2.4
/
IO Examples
/
Life
/
Life.icl
< prev
next >
Wrap
Text File
|
1997-04-28
|
8KB
|
231 lines
implementation module Life
import StdEnv, deltaPicture
:: Generation :== [[LifeCell]]
:: CellSize :== Int
:: ClickPoint :== (!Int,!Int)
:: LifeCell
= { x :: !Int
, y :: !Int
, age :: !Int
}
Colours :: {!Colour}
Colours =: {RedColour,MagentaColour,GreenColour,YellowColour,CyanColour,BlueColour}
ageToColour :: !Int -> Colour
ageToColour age
| age<=0 = Colours.[0]
| age>=5 = Colours.[5]
| otherwise = Colours.[age]
MakeGeneration :: Generation
MakeGeneration = []
MakeLifeCell :: !ClickPoint !CellSize -> LifeCell
MakeLifeCell (x,y) size
= {x=ClickPointToCell x size,y=ClickPointToCell y size,age=0}
where
ClickPointToCell :: !Int !Int -> Int
ClickPointToCell x size
| x<0 = x/size-1
| otherwise = x/size
NewLifeCell :: !Int !Int -> LifeCell
NewLifeCell x y
= {x=x,y=y,age=0}
// Rendering of LifeCells.
DrawCells :: !(LifeCell -> DrawFunction) !Generation -> [DrawFunction]
DrawCells f gen = map f (flatten gen)
DrawCell :: !CellSize !LifeCell !Picture -> Picture
DrawCell size {x,y,age} pict
# pict = SetPenColour (ageToColour age) pict
pict = FillRectangle ((px,py),(px+size,py+size)) pict
| size<=2 = pict
# pict = SetPenColour BlackColour pict
pict = DrawRectangle ((px-1,py-1),(px+size,py+size)) pict
= pict
where
px = x*size
py = y*size
EraseCell :: !CellSize !LifeCell !Picture -> Picture
EraseCell size {x,y} pict
= EraseRectangle ((px,py),(px+size,py+size)) pict
where
px = x*size
py = y*size
/* Insert a LifeCell to a Generation.
In a Generation LifeCells are ordered by increasing x-coordinate first, and by increasing y-coordinate second.
*/
InsertCell::!LifeCell !Generation -> Generation
InsertCell c1=:{x=x1} gen=:[cs=:[{x=x2,y=y2}:x2ys] : cs_xs]
| x2<x1 = [cs : InsertCell c1 cs_xs]
| x2==x1 = [InsertCelly c1 cs: cs_xs]
| otherwise = [[c1],cs : cs_xs]
where
InsertCelly :: !LifeCell ![LifeCell] -> [LifeCell]
InsertCelly c1=:{y=y1} [c2=:{x=x2,y=y2}:x2ys]
| y2<y1 = [c2 : InsertCelly c1 x2ys]
| y2==y1 = [c1 : x2ys]
| otherwise = [c1,c2: x2ys]
InsertCelly c1 _= [c1]
InsertCell c1 []
= [[c1]]
/* Remove a LifeCell from a Generation.
*/
RemoveCell::!LifeCell !Generation -> Generation
RemoveCell c1=:{x=x1,y=y1} gen=:[cs=:[{x=x2,y=y2}:x2ys]:cs_xs]
| x2<x1 = [cs:RemoveCell c1 cs_xs]
| x2>x1 = gen
# cs = RemoveCelly c1 cs
| isEmpty cs = cs_xs
| otherwise = [cs : cs_xs]
where
RemoveCelly :: !LifeCell ![LifeCell] -> [LifeCell]
RemoveCelly c1=:{y=y1} cs=:[c2=:{x=x2,y=y2}:x2ys]
| y2<y1 = [c2 : RemoveCelly c1 x2ys]
| y2==y1 = x2ys
| otherwise = cs
RemoveCelly _ _ = []
RemoveCell c [[]:cs_xs]
= RemoveCell c cs_xs
RemoveCell c _
= []
/* Calculate the new Generation (first tuple result) and the Generation of LifeCells that die (second tuple result).
*/
LifeGame::!Generation -> (!Generation,!Generation)
LifeGame gen
# (next,_,die) = NextGen gen gen
next = CelebrateSurvival next gen
= (next,die)
where
NextGen::!Generation Generation -> (!Generation,Generation,!Generation)
NextGen [[c=:{x,y}:cs_x]:cs_xs] gen
| Neighbours34 (Neighbours c gen) = (InsertCell c gennext1,new,diednext)
| otherwise = (gennext1,new,InsertCell c diednext)
where
(gennext,newbornsnext,diednext) = NextGen [cs_x:cs_xs] gen1
(gennext1,new) = NewBorns c newbornsnext gennext gen
gen1 = ShiftGeneration [cs_x:cs_xs] gen
Neighbours34 [_,_,_] = True
Neighbours34 [_,_,_,_] = True
Neighbours34 _ = False
NewBorns::!LifeCell Generation Generation Generation -> (!Generation,Generation)
NewBorns c newbornsnext gennext gen
= NewBorns1 (NewBornNeighbours c gen) newbornsnext gennext gen
where
NewBorns1 [c=:{x=x1,y=y1}:cs] newbornsnext gennext gen
| Neighbours3 (Neighbours c gen) = (InsertCell c gennext1,InsertCell c newbornsnext1)
| otherwise = next_genANDnewborns
where
(gennext1,newbornsnext1) = next_genANDnewborns
next_genANDnewborns = NewBorns1 cs newbornsnext gennext gen
Neighbours3::![LifeCell] -> Bool
Neighbours3 [_,_,_] = True
Neighbours3 _ = False
NewBorns1 [] newbornsnext gennext _
= (gennext,newbornsnext)
// NewBornNeighbours c gen -> dead neighbours of c in gen in decreasing order.
NewBornNeighbours::!LifeCell !Generation -> [LifeCell]
NewBornNeighbours {x,y} gen
= NewBornNeighbours1 (x-1) (x+1) (y-1) gen []
where
NewBornNeighbours1:: !Int !Int !Int !Generation ![LifeCell] -> [LifeCell]
NewBornNeighbours1 x xn y [cs=:[{x=x2}:_]:cs_xs] newborns
| x>xn = newborns
| x2<x = NewBornNeighbours1 x xn y cs_xs newborns
| x2==x = NewBornNeighbours2 x y (y+2) cs (NewBornNeighbours1 (x+1) xn y cs_xs newborns)
| otherwise = [NewLifeCell x y,NewLifeCell x (y+1),NewLifeCell x (y+2):NewBornNeighbours1 (x+1) xn y cs_xs newborns]
NewBornNeighbours1 x xn y [] newborns
| x>xn = newborns
| otherwise = [NewLifeCell x y,NewLifeCell x (y+1),NewLifeCell x (y+2):NewBornNeighbours1 (x+1) xn y [] newborns]
NewBornNeighbours2:: !Int !Int !Int ![LifeCell] ![LifeCell] -> [LifeCell]
NewBornNeighbours2 x y yn [c=:{x=x2,y=y2}:cs] cs_xs
| y>yn = cs_xs
| y2<y = NewBornNeighbours2 x y yn cs cs_xs
| y2==y = NewBornNeighbours2 x (y+1) yn cs cs_xs
| otherwise = [NewLifeCell x y:NewBornNeighbours2 x (y+1) yn cs cs_xs]
NewBornNeighbours2 x y yn [] cs_xs
| y>yn = cs_xs
| otherwise = [NewLifeCell x y:NewBornNeighbours2 x (y+1) yn [] cs_xs]
ShiftGeneration::!Generation !Generation -> Generation
ShiftGeneration [[c=:{x,y}:_]:_] gen = ShiftGeneration1 {c & x=x-2,y=y-2} gen
ShiftGeneration [[],[c=:{x,y}:_]:_] gen = ShiftGeneration1 {c & x=x-2,y=y-2} gen
ShiftGeneration partial_gen gen = gen
ShiftGeneration1::!LifeCell !Generation -> Generation
ShiftGeneration1 c=:{x=x1,y=y1} gen=:[[c2=:{x=x2,y=y2}:cs_x]:cs_xs]
| x2<x1 = ShiftGeneration1 c cs_xs
| x2==x1 && y2<y1 = ShiftGeneration1 c [cs_x:cs_xs]
| otherwise = gen
ShiftGeneration1 c [[]:cs_xs]
= ShiftGeneration1 c cs_xs
ShiftGeneration1 c _
= []
// Neighbours c gen -> neighbours of c in gen in decreasing order.
Neighbours::!LifeCell !Generation -> [LifeCell]
Neighbours {x,y} gen
= Neighbours1 (x-1) (x+1) (y-1) gen []
where
Neighbours1:: !Int !Int !Int !Generation ![LifeCell] -> [LifeCell]
Neighbours1 x xn y [cs=:[{x=x2,y=y2}:_]:cs_xs] neighbours
| x2<x = Neighbours1 x xn y cs_xs neighbours
| x2<=xn = Neighbours2 y (y+2) cs (Neighbours1 (x+1) xn y cs_xs neighbours)
| otherwise = neighbours
Neighbours1 _ _ _ [] neighbours = neighbours
Neighbours2:: !Int !Int ![LifeCell] ![LifeCell] -> [LifeCell]
Neighbours2 y yn [c=:{x=x2,y=y2}:cs] cs_xs
| y2<y = Neighbours2 y yn cs cs_xs
| y2<=yn = [c:Neighbours2 (y+1) yn cs cs_xs]
| otherwise = cs_xs
Neighbours2 _ _ [] cs_xs = cs_xs
NextGen [[]:cs_xs] gen
= NextGen cs_xs gen
NextGen _ _
= ([],[],[])
CelebrateSurvival :: !Generation !Generation -> Generation
CelebrateSurvival new old
= map (map (celebrate old)) new
where
celebrate :: !Generation !LifeCell -> LifeCell
celebrate old newcell
| found = {newcell & age=age+1}
= {newcell & age=age}
where
(found,age) = GetCellAge newcell old
GetCellAge :: !LifeCell !Generation -> (!Bool,!Int)
GetCellAge c1=:{x=x1} [xs=:[{x=x2}:_]:xss]
| x1<x2 = (False,0)
| x1>x2 = GetCellAge c1 xss
| otherwise = GetCellAge` c1 xs
GetCellAge _ _ = (False,0)
GetCellAge` :: !LifeCell ![LifeCell] -> (!Bool,!Int)
GetCellAge` c1=:{y=y1} [{y=y2,age}:xs]
| y1<y2 = (False,0)
| y1>y2 = GetCellAge` c1 xs
| otherwise = (True,age)
GetCellAge` _ _ = (False,0)